/*
 * Copyright Hundsun Technologies Inc. All Rights Reserved.
 */

package miner

import (
	"context"
	"time"

	"hundsun.com/hsl/hschain/common/log/logging"
	pbraft "hundsun.com/hsl/hschain/protos/consensus/raft"
)

const (
	goroutineTagRaftConsensusServer = "raftsrv"
)

// NewRaftConsensusServer 新建一个raft共识服务端
func NewRaftConsensusServer(module *RaftMiner) *RaftConsensusServer {
	return &RaftConsensusServer{
		module: module,
		log:    module.Log.WithField(logging.LogFieldGoroutine, goroutineTagRaftConsensusServer),
	}
}

// RaftConsensusServer raft共识服务端
type RaftConsensusServer struct {
	module *RaftMiner
	log    logging.Log
}

// Start 启动grpc服务
//func (s *RaftConsensusServer) Start() error {
//	grpcServer := grpc.NewServer(grpcutil.GetDefaultServerOptions()...)
//	pbraft.RegisterRaftConsensusServer(grpcServer, s)
//	listener, err := net.Listen("tcp", s.module..String())
//	if err != nil {
//		return err
//	}
//	go grpcServer.Serve(listener)
//	s.log.Infof("listening at %s", s.module.ListenAddress.String())
//	return nil
//}

// RequestVote 请求选票
func (s *RaftConsensusServer) RequestVote(ctx context.Context, args *pbraft.RequestVoteArgs) (*pbraft.RequestVoteReply, error) {
	cm := s.module.cm
	cm.mu.Lock()
	defer cm.mu.Unlock()
	reply := pbraft.RequestVoteReply{
		Term:        args.Term,
		VoteGranted: false,
	}
	if cm.state == Dead {
		return &reply, nil
	}
	s.log.Infof("Receive RequestVote: %v [currentTerm=%d, votedFor=%d]", args, cm.currentTerm, cm.votedFor)

	// 请求中的任期大于本地任期，转换为追随者状态
	if args.Term > cm.currentTerm {
		s.log.Info("... term out of date in RequestVote, and become Follower")
		cm.becomeFollower(args.Term)
	}

	// 任期相同，且未投票或已投票给当前请求同伴，则返回赞成投票；否则，返回反对投票。
	// 除此之外不对竞选者做任何限定，如果一个竞选者成功竞选为领导者，应进行区块同步，保证blockSequence是最新的
	if cm.currentTerm == args.Term &&
		(cm.votedFor == -1 || cm.votedFor == args.CandidateId) {
		reply.VoteGranted = true
		cm.votedFor = args.CandidateId
		cm.electionResetEvent = time.Now()
	} else {
		reply.VoteGranted = false
	}
	reply.Term = cm.currentTerm
	s.log.Infof("... RequestVote reply: %v", reply)
	return &reply, nil
}

// CommitRequest 提交请求
func (s *RaftConsensusServer) CommitRequest(ctx context.Context, args *pbraft.CommitRequestArgs) (*pbraft.CommitRequestReply, error) {
	cm := s.module.cm
	cm.mu.Lock()
	defer cm.mu.Unlock()
	reply := pbraft.CommitRequestReply{
		Term:              args.Term,
		Success:           false,
		LastBlockSequence: args.LastBlockSequence,
	}
	if cm.state == Dead {
		return &reply, nil
	}
	if args.BeingCommit {
		s.log.Infof("Receive CommitRequest: %v", args)
	}

	// 请求中的任期大于本地任期，转换为追随者状态，保证一个任期内只有一个leader
	if args.Term > cm.currentTerm {
		s.log.Info("... term out of date in RequestVote, and become Follower")
		cm.becomeFollower(args.Term)
	}

	reply.Success = false
	if args.Term == cm.currentTerm {
		// 如果当前状态不是追随者，则变为追随者,保证一个任期之内只有一个领导者
		if cm.state != Follower {
			cm.becomeFollower(args.Term)
		}
		cm.electionResetEvent = time.Now()

		// 如果领导者请求提交
		if args.BeingCommit {
			reply.Success = true
		}
	}

	reply.Term = cm.currentTerm
	if args.BeingCommit {
		s.log.Info("CommitRequest reply: %v", reply)
	}
	return &reply, nil
}
